package com.baijia.web.service.impl;

import com.baijia.authentication.ThirdLogin;
import com.baijia.commons.lang.utils.http.HttpClientUtils;
import com.baijia.dao.ThirdLoginAccountDao;
import com.baijia.dao.po.Passport;
import com.baijia.dao.po.ThirdLoginAccount;
import com.baijia.exception.ErrorCode;
import com.baijia.services.PassportService;
import com.baijia.util.DecriptUtil;
import com.baijia.web.dto.response.MobileResponse;
import com.baijia.web.service.IThirdLoginService;
import com.baijia.web.util.ThirdLoginUtil;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.annotation.Resource;

/**
 * Created by dudu on 16/7/12.
 */
@Service
public class ThirdLoginServiceImpl implements IThirdLoginService {

    @Resource
    private ThirdLoginAccountDao thirdLoginAccountDao;

    @Resource
    private PassportService passportService;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public String login(String channel, String code, MobileResponse response) {
        String responseResult;
        String uid = null;
        String username = null;
        String nickname = null;
        switch (channel) {

            case ThirdLogin.WEIBO:
                responseResult =
                    getAccessToken(ThirdLoginUtil.WEIBO_CLIENT_ID, ThirdLoginUtil.WEIBO_CLIENT_SECRET, code,
                        ThirdLoginUtil.WEIBO_REDIRECT_URL, ThirdLoginUtil.WEIBO_ACCESS_TOKEN_URL);
                if (StringUtils.isNotBlank(responseResult)) {
                    JSONObject result = JSON.parseObject(responseResult);
                    if (StringUtils.isNotBlank(result.getString("error_code"))) {
                        response.fail().msg(result.getString("error_description"));
                        return null;
                    } else {
                        uid = result.getString("uid");
                    }
                    String access_token = result.getString("access_token");
                    Map<String, String> params = new HashMap<>(4);
                    params.put("access_token", access_token);
                    params.put("uid", uid);
                    String weiboUserInfo = HttpClientUtils.doGet(ThirdLoginUtil.WEIBO_USER_INFO_URL, params);
                    logger.info("get nickname response from weibo: {}", weiboUserInfo);
                    JSONObject userInfoJson = JSON.parseObject(weiboUserInfo);
                    nickname = userInfoJson.getString("screen_name");
                    logger.info("uid from weibo : {}, nickname from weibo: {}", uid, nickname);
                }
                username = handleAccountWithUid(uid, nickname, response, ThirdLogin.WEIBO);
                break;
            case ThirdLogin.QQ:
                responseResult =
                    getAccessToken(ThirdLoginUtil.QQ_CLIENT_ID, ThirdLoginUtil.QQ_CLIENT_SECRET, code,
                        ThirdLoginUtil.QQ_REDIRECT_URL, ThirdLoginUtil.QQ_ACCESS_TOKEN_URL);
                if (StringUtils.isNotBlank(responseResult)) {
                    String accessTokenParam = responseResult.split("&")[0];
                    String accessToken = accessTokenParam.split("=")[1];
                    Map<String, String> params = new HashMap<>(4);
                    params.put("access_token", accessToken);
                    String result = HttpClientUtils.doPost(ThirdLoginUtil.QQ_OPENID_URL, params);
                    uid = result.substring(result.indexOf("\"openid\":\"") + 10, result.indexOf("\"}"));
                    // 获取用户信息
                    params.put("oauth_consumer_key", ThirdLoginUtil.QQ_CLIENT_ID);
                    params.put("openid", uid);
                    String QQUserInfo = HttpClientUtils.doPost(ThirdLoginUtil.QQ_USER_INFO_URL, params);
                    if (StringUtils.isNotEmpty(QQUserInfo)) {
                        JSONObject userInfo = JSON.parseObject(QQUserInfo);
                        if (userInfo.getInteger("ret") == 0) {
                            nickname = userInfo.getString("nickname");
                        }
                    }
                    logger.info("openid from qq : {}, nickname from qq: {}", uid, nickname);
                } else {
                    response.fail().msg("login fail");
                    return null;
                }

                username = handleAccountWithUid(uid, nickname, response, ThirdLogin.QQ);
                break;
            case ThirdLogin.RENREN:
                responseResult =
                    getAccessToken(ThirdLoginUtil.RENREN_CLIENT_ID, ThirdLoginUtil.RENREN_CLIENT_SECRET, code,
                        ThirdLoginUtil.RENREN_REDIRECT_URL, ThirdLoginUtil.RENREN_ACCESS_TOKEN_URL);
                if (StringUtils.isNotBlank(responseResult)) {
                    JSONObject result = JSON.parseObject(responseResult);
                    logger.info("responseResult from renren to json:{}", result.toString());
                    if (StringUtils.isNotBlank(result.getString("error_code"))) {
                        response.fail().msg(result.getString("error_description"));
                        return null;
                    } else {
                        uid = ((JSONObject) result.get("user")).getString("id");
                        nickname = ((JSONObject) result.get("user")).getString("name");
                        logger.info("uid from renren :{}, nickname from renren :{}", uid, nickname);
                        username = handleAccountWithUid(uid, nickname, response, ThirdLogin.RENREN);
                    }
                }
                break;
            case ThirdLogin.ALIPAY:
                responseResult =
                    getAlipayAccessToken(ThirdLoginUtil.ALIPAY_CLIENT_ID, code, ThirdLoginUtil.ALIPAY_ACCESS_TOKEN_URL);
                if (StringUtils.isNotBlank(responseResult)) {
                    JSONObject result = JSON.parseObject(responseResult);
                    if (StringUtils.isNotBlank(result.getString("error_response"))) {
                        response.fail().msg(result.getString("error_response"));
                        return null;
                    } else {
                        uid = ((JSONObject) result.get("alipay_system_oauth_token_response")).getString("user_id");
                        String access_token =
                            ((JSONObject) result.get("alipay_system_oauth_token_response")).getString("access_token");
                        String AlipayUserInfo = getAlipayUserInfo(ThirdLoginUtil.ALIPAY_USER_INFO_URL, access_token);
                        JSONObject alipayUserInfoJson = JSON.parseObject(AlipayUserInfo);
                        nickname =
                            ((JSONObject) alipayUserInfoJson.get("alipay_user_userinfo_share_response"))
                                .getString("nick_name");
                        logger.info("uid from alipay :{}, nickname from alipay :{}", uid, nickname);

                        username = handleAccountWithUid(uid, nickname, response, ThirdLogin.ALIPAY);
                    }
                }
                break;
            case ThirdLogin.WECHAT:
                responseResult =
                    getWechatAccessToken(ThirdLoginUtil.WECHAT_CLIENT_ID, ThirdLoginUtil.WECHAT_CLIENT_SECRET, code,
                        ThirdLoginUtil.WECHAT_ACCESS_TOKEN_URL);
                if (StringUtils.isNotBlank(responseResult)) {
                    JSONObject result = JSON.parseObject(responseResult);
                    if (StringUtils.isNotBlank(result.getString("errcode"))) {
                        response.fail().msg(result.getString("errmsg"));
                        return null;
                    } else {
                        uid = result.getString("openid");
                        String access_token = result.getString("access_token");
                        Map<String, String> params = new HashMap<>(4);
                        params.put("access_token", access_token);
                        params.put("openid", uid);
                        params.put("lang", "zh_CN");
                        String WeChatUserInfo = HttpClientUtils.doPost(ThirdLoginUtil.WECHAT_USER_INFO_URL, params);
                        JSONObject userInfo = JSON.parseObject(WeChatUserInfo);
                        if (StringUtils.isEmpty(userInfo.getString("errcode"))) {
                            nickname = userInfo.getString("nickname");
                        }
                        logger.info("uid from wechat :{}, nickname from wechat :{}", uid, nickname);
                    }
                }
                username = handleAccountWithUid(uid, nickname, response, ThirdLogin.WECHAT);
                break;
            default:
                break;
        }

        return username;

    }

    private String getWechatAccessToken(String clientId, String clientSecret, String code, String postUrl) {
        Map<String, String> params = new HashMap<>();
        params.put("appid", clientId);
        params.put("secret", clientSecret);
        params.put("grant_type", "authorization_code");
        params.put("code", code);
        logger.info("postUrl: {}", postUrl);
        String responseResult = HttpClientUtils.doGet(postUrl, params);
        logger.info("login from wechat get response : {}", responseResult);
        return responseResult;
    }

    private String getAlipayAccessToken(String clientId, String code, String postUrl) {
        Map<String, String> params = new TreeMap<>();
        params.put("app_id", clientId);
        params.put("charset", "GBK");
        params.put("sign_type", "RSA");
        params.put("timestamp", "2016-07-22 16:50:08");
        params.put("grant_type", "authorization_code");
        params.put("version", "1.0");
        params.put("code", code);
        params.put("method", "alipay.system.oauth.token");
        StringBuilder stringBuilder = new StringBuilder();
        Set<String> keys = params.keySet();
        for (String key : keys) {
            stringBuilder.append(key).append("=").append(params.get(key)).append("&");
        }
        String signStr = stringBuilder.substring(0, stringBuilder.length() - 1);
        logger.info("params send to alipay: {}", signStr);
        try {
            String sign = DecriptUtil.rsaSign(signStr, DecriptUtil.PRIVATE_KEY, "");
            logger.info("sign: {}", sign);
            params.put("sign", sign);
        } catch (Exception e) {
            logger.warn("login by alipay get accessToken occurs sign error!");
        }

        String responseResult = HttpClientUtils.doPost(postUrl, params);
        logger.info("login from alipay get response : {}", responseResult);
        return responseResult;
    }

    private String getAlipayUserInfo(String postUrl, String access_token) {
        Map<String, String> params = new TreeMap<>();
        params.put("app_id", ThirdLoginUtil.ALIPAY_CLIENT_ID);
        params.put("auth_token", access_token);
        params.put("charset", "GBK");
        params.put("method", "alipay.user.userinfo.share");
        params.put("sign_type", "RSA");
        params.put("timestamp", "2016-07-22 16:50:08");
        params.put("version", "1.0");
        StringBuilder stringBuilder = new StringBuilder();
        Set<String> keys = params.keySet();
        for (String key : keys) {
            stringBuilder.append(key).append("=").append(params.get(key)).append("&");
        }
        String signStr = stringBuilder.substring(0, stringBuilder.length() - 1);
        logger.info("params send to alipay: {}", signStr);
        try {
            String sign = DecriptUtil.rsaSign(signStr, DecriptUtil.PRIVATE_KEY, "");
            logger.info("sign: {}", sign);
            params.put("sign", sign);
        } catch (Exception e) {
            logger.warn("login by alipay get AlipayUserInfo occurs sign error!");
        }

        String responseResult = HttpClientUtils.doPost(postUrl, params);
        logger.info("login from alipay get response : {}", responseResult);
        return responseResult;
    }

    private String getAccessToken(String clientId, String clientSecret, String code, String redirectUri, String postUrl) {
        Map<String, String> params = new HashMap<>();
        params.put("client_id", clientId);
        params.put("client_secret", clientSecret);
        params.put("grant_type", "authorization_code");
        params.put("code", code);
        params.put("redirect_uri", redirectUri);
        logger.info("postUrl: {}", postUrl);
        logger.info("params: {}", params);
        String responseResult = HttpClientUtils.doPost(postUrl, params);
        logger.info("login from thirdLogin get response : {}", responseResult);
        return responseResult;
    }

    private String handleAccountWithUid(String uid, String nickname, MobileResponse response, String channel) {
        if (StringUtils.isNotBlank(uid)) {
            ThirdLoginAccount thirdLoginAccount = thirdLoginAccountDao.getByUid(uid, channel);
            if (thirdLoginAccount != null) {
                Long passportId = thirdLoginAccount.getPassportId();
                if (passportId == null || passportId == 0) {
                    // 通过第三方登录 但是尚未绑定手机号码
                    response.setCode(ErrorCode.NEED_BIND_ACCOUNT.getCode());
                    response.setMsg(ErrorCode.NEED_BIND_ACCOUNT.getMessage());
                    response.setData(thirdLoginAccount.getId());
                } else if (passportId > 0) {
                    Passport passport = passportService.getById(passportId);
                    String username = passport.getMobile();
                    return username;
                }
            } else {
                thirdLoginAccount = new ThirdLoginAccount();
                thirdLoginAccount.setUid(uid);
                thirdLoginAccount.setNickName(nickname);
                thirdLoginAccount.setChannel(channel);
                Long accountId = thirdLoginAccountDao.save(thirdLoginAccount);
                if (accountId > 0) {
                    response.setCode(ErrorCode.NEED_BIND_ACCOUNT.getCode());
                    response.setMsg(ErrorCode.NEED_BIND_ACCOUNT.getMessage());
                    response.setData(accountId);
                } else {
                    response.fail().msg(ErrorCode.THIRD_LOGIN_ERROR.getMessage());
                }
            }
        }
        return null;
    }

}
